package com.zhrj.exam.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhrj.exam.entity.BladeUser;
import com.zhrj.exam.mapper.BladeUserMapper;
import com.zhrj.exam.configuration.MinIOConfig;
import com.zhrj.util.MinIOUtil;
import com.zhrj.exam.service.BladeUserService;
import io.minio.ObjectWriteResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BladeUserServiceImpl extends ServiceImpl<BladeUserMapper, BladeUser> implements BladeUserService {

    @Autowired
    private MinIOUtil minIOUtil;
    @Autowired
    private MinIOConfig minIOConfig; // 用于获取配置的存储桶名称
    @Autowired
    private BladeUserMapper bladeUserMapper;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public boolean batchInsertUsers(List<BladeUser> userList) {
        // 每 1000 条数据进行批量写入，防止内存溢出
        return this.saveBatch(userList, 1000);
    }

    @Override
    public List<Long> getExistUserIds() {
        List<BladeUser> userList = super.list();
        return userList.stream()
                .map(BladeUser::getId)
                .collect(Collectors.toList());
    }

    @Override
    public void exportUsersToExcel() {

        List<BladeUser> userList = super.list();

        String fileName = "user_export_" + System.currentTimeMillis() + ".xlsx";
        File excelFile = new File(fileName);

        try {
            // 使用EasyExcel写入数据
            EasyExcel.write(excelFile, BladeUser.class)

                    .sheet("用户列表") // Sheet名称
                    .doWrite(userList); // 写入数据

            /*
            * 上传到minio服务器
            * */
            String bucketName = minIOConfig.getBucketName(); // 从配置获取存储桶名
            String objectName = "exports/user_list.xlsx";    // Minio中的路径和文件名
            try {
                // 调用上传方法
                ObjectWriteResponse response = minIOUtil.uploadFile(bucketName, objectName, excelFile.getAbsolutePath());
                log.info("文件上传成功，响应: {}", response);

                // 验证文件是否存在（可选）
                boolean isExist = minIOUtil.isObjectExist(bucketName, objectName);
                if (isExist) {
                    log.info("文件已确认存在于Minio存储桶中");
                }
            } catch (Exception e) {
                log.error("文件上传失败: {}", e.getMessage());
                throw new RuntimeException("文件上传失败", e);
            }
            log.info("Excel文件生成成功，路径: " + excelFile.getAbsolutePath());
        } catch (Exception e) {
            throw new RuntimeException("生成Excel文件失败", e);
        }
    }

    @Override
    public Integer update(BladeUser bladeUser) {
        return bladeUserMapper.updateById(bladeUser);
    }

    @Override
    @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000))
    public List<BladeUser> pageQuery(String url) throws JsonProcessingException, InterruptedException {
        String clientId = "saber";
        String clientSecret = "saber_secret";
        String auth = clientId + ":" + clientSecret;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization","Basic" + encodedAuth);
        String token = (String) redisTemplate.opsForValue().get("accessToken");
        String tokenType = (String) redisTemplate.opsForValue().get("tokenType");
        String auth1 = tokenType + " " + token;
        headers.set("blade-auth",auth1);
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                httpEntity,
                String.class
        );


        JsonNode jsonNode = objectMapper.readTree(response.getBody());  // 解析整个 JSON 响应体
        // 获取 records 数组
        JsonNode recordsNode = jsonNode.get("records");
        // 将 records 数组转换为 List<BladeUser>
        List<BladeUser> bladeUsers = objectMapper.readValue(recordsNode.toString(), new TypeReference<List<BladeUser>>() {});
        return bladeUsers;

    }

    @Recover
    public List<BladeUser> recover(Throwable e, String url) {
        log.error("服务降级: 调用 {} 失败，原因: {}", url, e.getMessage());
        // 返回一个空列表表示降级
        return Collections.emptyList();
    }

}
